﻿#include "YEncoder.h"
#include <QDebug>
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/avutil.h"
#include "libavutil/opt.h"
}



//////////////////////////////////////////////////////////////
   /// 编码数据 线程安全 每次新创建AVPacket
   /// @para frame 空间由用户维护
   /// @return 失败范围nullptr 返回的AVPacket用户需要通过av_packet_free 清理
AVPacket* YEncoder::Encode(const AVFrame* frame)
{
	if (!frame)return nullptr;
	std::unique_lock<std::mutex>lock(m_mutex);
	if (!m_context)return nullptr;
	av_frame_make_writable((AVFrame*)frame);
	//发送到编码线程
	auto re = avcodec_send_frame(m_context, frame);
	if (re != 0)
	{
		PrintError(re, "avcodec_send_frame");
		return nullptr;
	}
	auto pkt = av_packet_alloc();
	//接收编码线程数据
	re = avcodec_receive_packet(m_context, pkt);
	if (re == 0)
	{
		return pkt;
	}
	av_packet_free(&pkt);
	if (re == AVERROR(EAGAIN) || re == AVERROR_EOF)
	{
		qDebug() << "出错或者到达尾部";
		PrintError(re, "avcodec_receive_packet");
		return nullptr;
	}
	else {
		PrintError(re, "编码");
	}
	return nullptr;
}


//////////////////////////////////////////////////////////////
//返回所有编码缓存中AVPacket
std::vector<AVPacket*> YEncoder::End()
{
	std::vector<AVPacket*> res;
	std::unique_lock<std::mutex>lock(m_mutex);
	if (!m_context)return res;
	auto re = avcodec_send_frame(m_context, NULL); //发送NULL 获取缓冲
	if (re != 0)return res;
	while (re >= 0)
	{
		auto pkt = av_packet_alloc();
		re = avcodec_receive_packet(m_context, pkt);
		if (re != 0)
		{
			av_packet_free(&pkt);
			break;
		}
		res.push_back(pkt);
	}
	return res;
}


//像素格式转换
void YEncoder::InitSwsCtx()
{
	std::unique_lock<std::mutex>lock(mMutex);
	if (!mContext)return;
	swsCtx = sws_getCachedContext(swsCtx,
		mContext->width, mContext->height, AV_PIX_FMT_BGRA,//输入的宽高及像素格式
		mContext->width, mContext->height,//输出的宽高
		AV_PIX_FMT_YUV420P,//输出的像素格式
		SWS_BILINEAR,//双线性插值算法
		0, 0, 0
	);
	if (!swsCtx)
	{
		qDebug() << "sws_getCachedContext failed!";
	}
}

void YEncoder::scale(uint8_t* inData, AVFrame* frame)
{
	std::unique_lock<std::mutex>lock(mMutex);
	if (!mContext)return;

	const uint8_t* srcData[AV_NUM_DATA_POINTERS];
	srcData[0] = inData;
	int srcLines[AV_NUM_DATA_POINTERS];
	srcLines[0] = mContext->width * 4;
	int ret = sws_scale(swsCtx
		, srcData, srcLines, 0, mContext->height,
		frame->data, frame->linesize
	);
	if (ret <= 0)
	{
		PrintError(ret, "scale");
	}
}
void YEncoder::Release()
{
	if (swsCtx)
	{
		sws_freeContext(swsCtx);
		swsCtx = nullptr;
	}
}

YEncoder::YEncoder()
{

}

YEncoder::~YEncoder()
{
}
